/**
 * 
 */
package container;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import servlet.annotation.Parameter;
import servlet.annotation.RequestProcessing;
import servlet.annotation.RequestProcessor;

import logging.Level;
import logging.Logger;

import org.apache.commons.io.FileUtils;

/**
 * @author think
 * 
 */
public class AnnotionHelper {

	private static final Logger LOGGER = Logger.getLogger(AnnotionHelper.class
			.getName());

	/**
	 * 读取类上面的注解信息
	 * 
	 * @param packageName
	 * @return
	 * @throws IOException
	 */
	public Set<Class<?>> readAnnotoionClazz(String packageName)
			throws IOException {
		Set<Class<?>> ret = new HashSet<Class<?>>();
		// 读取包和子包的东西里面所有的类
		Set<URL> urls = readLeve1(packageName);
		Set<URL> clazzUrls = readClazzURL(urls);
		MyClassLoader myclzzLoader = new MyClassLoader();
		for (URL url : clazzUrls) {
			byte[] clazzContent = FileUtils.readFileToByteArray(new File(url
					.getFile()));
			try {
				Class<?> clazz = myclzzLoader.findClass(clazzContent);
				Annotation[] annotations = clazz.getAnnotations();
				if (annotations == null) {
					continue;
				} else {
					for (Annotation annotation : annotations) {
						if (annotation.annotationType().equals(
								RequestProcessor.class)) {
							LOGGER.debug("is annnotation [" + clazz.getName()
									+ "]");
							ret.add(clazz);
						}
					}
				}
			} catch (Exception e) {
				LOGGER.log(Level.WARN, "load clazz error", e);
			}

		}
		return ret;
	}

	/**
	 * 读取方法上的注解信息 返回方法和路径的对应关系 方法参数类型和默认值，这些东西可以封装在processorInfo的类中
	 * 
	 * @return
	 */
	public Map<String, ProcessorInfo> readMethodAnnotation(
			Set<Class<?>> clazzSet) {
		MyContainer myContainer = MyContainer.getInstance();
		Map<String, ProcessorInfo> processorInfoMap = myContainer
				.getProcessorInfoMap();
		for (Class clazz : clazzSet) {
			Method[] methods = clazz.getMethods();
			if (methods == null) {
				continue;
			}
			for (Method method : methods) {
				Annotation[] annotations = method.getAnnotations();
				if (annotations == null) {
					continue;
				}
				ProcessorInfo processorInfo = new ProcessorInfo();
				processorInfo.setMethod(method);
				// 获取注解的信息，该信息把url路径和方法名对应起来
				for (Annotation annotation : annotations) {
					RequestProcessing requestProcessing = (RequestProcessing) annotation;
					String[] values = requestProcessing.value();
					for (String value : values) {
						LOGGER.info("path:" + value);
						processorInfoMap.put(value, processorInfo);
					}
				}
				// 获取参数类型
				String mName = method.getName();
				Class<?>[] pclazzs = method.getParameterTypes();
				processorInfo.setParameterTypes(pclazzs);
				LOGGER.debug("mName:" + mName);
				// 获取注解默认值
				String[] defaultValues = new String[pclazzs.length];
				String[] parameterNames = new String[pclazzs.length];
				int seq = 0, index = 0;
				Annotation[][] pannotations = method.getParameterAnnotations();
				for (Annotation[] pannotation : pannotations) {
					if (pannotation.length > 0) {
						LOGGER.debug("pannotation-AAAAAAAAAAAA:"
								+ pannotation.length);
						Parameter parameter = (Parameter) pannotation[0];
						String pName = parameter.name();
						String defaultValue = parameter.defaultValue();
						defaultValues[seq++] = defaultValue;
						parameterNames[index++] = pName;
						LOGGER.debug("pName:" + pName);
						LOGGER.debug("defaultValue:" + defaultValue);
					}
				}

				processorInfo.setDefaultValues(defaultValues);
				processorInfo.setParameterNames(parameterNames);

			}
		}

		return processorInfoMap;
	}

	/**
	 * @param urls
	 * @return
	 * @throws URISyntaxException
	 */
	private Set<URL> readClazzURL(Set<URL> urls) {
		final Set<URL> clazzURLs = new LinkedHashSet<URL>();
		for (URL url : urls) {
			try {
				File rootFile = new File(url.toURI());
				Collection<File> c1 = FileUtils.listFiles(rootFile,
						new String[] { "class" }, true);
				for (File ff : c1) {
					clazzURLs.add(ff.toURI().toURL());
				}
			} catch (Exception e) {
				LOGGER.log(Level.WARN, "readClazzURL failed", e);
			}
		}
		return clazzURLs;
	}

	/**
	 * @param packageName
	 * @return
	 */
	private Set<URL> readLeve1(String packageName) {
		final Set<URL> urls = new LinkedHashSet<URL>();
		try {
			// 转换为"net/kaixinpig/processor"格式
			String path = packageName.replaceAll("\\.", "/");
			final Enumeration<URL> resources = Thread.currentThread()
					.getContextClassLoader().getResources(path);
			URL url = null;

			while (resources.hasMoreElements()) {
				url = (URL) resources.nextElement();
				urls.add(url);
				LOGGER.info("url:[" + url.toString() + "]");
			}
		} catch (final IOException e) {
			LOGGER.log(Level.ERROR, "get the ROOT Rescources error", e);
		}
		return urls;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		LOGGER.info("start");
		AnnotionHelper annotionTest = new AnnotionHelper();
		try {
			Set<Class<?>> clazzSet = annotionTest
					.readAnnotoionClazz("net.kaixinpig");
			annotionTest.readMethodAnnotation(clazzSet);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		LOGGER.info("end");
	}

}
